package ace.states;

import ace.Main;
import ace.game.entity.player.Profile;
import ace.game.entity.Entity;
import java.util.Vector;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.game.GameCanvas;
import ace.game.entity.body.BodyFactory;
import ace.game.entity.bullet.Bullet;
import ace.game.entity.enemy.Enemy;
import ace.game.entity.enemy.EnemyData;
import ace.game.entity.enemy.EnemyFactory;
import ace.game.entity.pickup.Pickup;
import ace.game.entity.pickup.PickupData;
import ace.game.entity.pickup.PickupFactory;
import ace.game.entity.player.Player;
import ace.game.entity.weapon.Weapon;
import ace.game.entity.weapon.WeaponFactory;
import ace.game.level.Level;
import ace.game.particle.ParticleEmitter;
import ace.game.particle.ParticleEmitterFactory;
import ace.geometry.Vertex2D;
import ace.system.BitmapFont;

import ace.system.StateManager;
import ace.system.Utilities;
import ace.system.sound.SFXPlayer;
import ace.system.sound.SimplePlayer;
import java.io.IOException;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Image;

public class StateGame extends GameState {
	public StateGame(int level, Profile profile) {
		//Super
		super(GameState.GAME);

		// allow state to hold keys
		mKeysHoldable = true;

        // create entities
		mParticleEmitters	= new Vector();
        mPickups            = new Vector();

		// create deleter
		mDeleteEmitters		= new Vector();
		mDeleteEnemies		= new Vector();
        mDeletePickups      = new Vector();

		// persist parameters
		mCurrentLevel   = level;
        mProfile        = profile;

        // make images
        try {
            mProfileBoard       = Image.createImage(Utilities.INTERFACE_FOLDER + "/profile_board.png");
            mHealthBar          = Image.createImage(Utilities.INTERFACE_FOLDER + "/health_bar.png");
            mLife               = Image.createImage(Utilities.PICKUP_FOLDER + "/life.png");
            mScoreBoardImage    = Image.createImage(Utilities.INTERFACE_FOLDER + "/score.png");
            mPauseBoardImage    = Image.createImage(Utilities.INTERFACE_FOLDER + "/pause.png");
			mPauseSelectionImage = Image.createImage(Utilities.INTERFACE_FOLDER + "/selection.png");

            // make texts
            mScoreLabelStringImage  = new Image[4];
            mPauseStringItems       = new Image[3];

            mScoreLabelStringImage[0]   = BitmapFont.getFont(BitmapFont.BITSUMISHI_BLUE).renderTransparentText("Enemy killed", 0x000000);
            mScoreLabelStringImage[1]   = BitmapFont.getFont(BitmapFont.BITSUMISHI_BLUE).renderTransparentText("Remaining life", 0x000000);
            mScoreLabelStringImage[2]   = BitmapFont.getFont(BitmapFont.BITSUMISHI_BLUE).renderTransparentText("Money added", 0x000000);
            mScoreLabelStringImage[3]   = BitmapFont.getFont(BitmapFont.BITSUMISHI_BLUE).renderTransparentText("Rank", 0x000000);
            mPressFireStringImage       = BitmapFont.getFont(BitmapFont.BITSUMISHI_BLUE).renderTransparentText("Press fire to continue...", 0x000000);
            mPauseStringItems[0]        = BitmapFont.getFont(BitmapFont.BITSUMISHI_BLUE).renderTransparentText("Continue", 0x000000);
            mPauseStringItems[1]        = BitmapFont.getFont(BitmapFont.BITSUMISHI_BLUE).renderTransparentText("Restart", 0x000000);
            mPauseStringItems[2]        = BitmapFont.getFont(BitmapFont.BITSUMISHI_BLUE).renderTransparentText("Abort", 0x000000);
        } catch (IOException iEx) {}

		//Initialize toggle for holding score panel when lose (therefore score panel and pause panel won't be shown altogether)
		mIsLoseScoreOK = false;

		if(level % 2 == 1)	StateManager.instance().getSimplePlayer().setSong(Utilities.BGM_FOLDER + "/game1.mid", "audio/mid", SimplePlayer.LOOP_INF);
		else				StateManager.instance().getSimplePlayer().setSong(Utilities.BGM_FOLDER + "/game2.mid", "audio/mid", SimplePlayer.LOOP_INF);
		StateManager.instance().getSimplePlayer().startPlayer();

		//Initialize level
		initLevel();
	}

	protected void initLevel(){
		//Create level
		mLevel      = new Level(Utilities.LEVEL_FOLDER + "/" + mCurrentLevel + ".xml");
        mEnemies    = mLevel.getEnemyWaves();
        mPickups    = mLevel.getPickups();

		// Initialize draw area
		mDrawStartX = 0;
		mDrawStartY = (mLevel.getMap().getHeight() - StateManager.instance().getRow() - 1) * Utilities.TILE_HEIGHT;
		mDrawEndX   = mDrawStartX + StateManager.instance().getColumn() * Utilities.TILE_WIDTH;
		mDrawEndY   = mDrawStartY + StateManager.instance().getRow() * Utilities.TILE_HEIGHT;
        
		// initialize gameplay data
		mScrollSpeed    = 0.05f;
        mPaused         = false;
        mPauseSelectedItem = 0;

        // initialize player data
		mPlayer             = mProfile.buildPlayer();
		mPlayer.position.x  = mDrawStartX + StateManager.instance().getWidth() / 2;
		mPlayer.position.y  = mDrawStartY + StateManager.instance().getHeight() / 2;
        mPlayer.setImmortal(true);

        // initialize winning and scoring stuffs

        mScoreStringImage   = BitmapFont.getFont(BitmapFont.BITSUMISHI_BLUE).renderTransparentText("0", 0x000000);
        mInitialLifeCount   = mPlayer.getLife() + 1;
        mInitialEnemyCount  = mEnemies.size();
        mWinning            = false;
        mLosing             = false;
        mEndDelay           = 0;
        mBlinkingTime       = 0;
	}
	
	public void addScore(int score) {
        mPlayer.addScore(score);
        mScoreStringImage   = BitmapFont.getFont(BitmapFont.BITSUMISHI_BLUE).renderTransparentText("" + mPlayer.getScore(), 0x000000);
	}

	public void onPause(){
		if (!mWinning) {
            mPaused = true;
        }
	}

	public void onResume(){
		
	}

	public void keyPressed(int key) {
		//Super
		super.keyPressed(key);

		//Skip if dialog or won

		//Is right pressed?
		if (key == -7 || key == 35) checkRightButton();
		else if (key == -6)			checkLeftButton();
	}

	public void update(long time, int keys) {

		//Super
		super.update(time, keys);

		if ((keys & GameCanvas.FIRE_PRESSED) != 0) checkFireKey();

        if (mWinning || mLosing) {
            // press fire blinking thingy
            mBlinkingTime += time;
        }
        if (mPaused) {
            // let the keys not holdable (to prevent continous pause selection movement)
            mKeysHoldable = false;
            checkPause(time, keys);
            return;
        }
        // let the keys holdable
        mKeysHoldable = true;

		// scrolling to top
		mDrawStartY	-= mScrollSpeed * time;

        if (mDrawStartY > 0) {
            mDrawEndY	-= mScrollSpeed * time;
        } else {
            mDrawStartY = 0;
            mScrollSpeed = 0;
        }

        checkCollision();
		checkPlayer(time, keys);
		checkEnemy(time);
		checkParticles(time);
        checkPickups(time);

        checkEndCondition(time);
	}
	
	protected void checkRightButton() {		
		//Cancel sound StateManager.instance().playSFX("/cancel.wav");
		/*StateManager.instance().getSFXPlayer().playSFX(SFXPlayer.SFX_CANCEL);
        Vector param = new Vector();
        param.addElement(mProfile);
        StateManager.instance().goTo(GameState.MENU, param, false);*/

		if (!mWinning) {
            mPaused = !mPaused;
        }
	}

    protected void checkLeftButton() {
        
    }

	protected void checkFireKey() {
		//If in the middle of the game
		if (mWinning) {
            Vector param = new Vector();
            mProfile.setLevel(mProfile.getLevel() + 1);
            mProfile.addTotalMissionScore(mFinalScore);
            param.addElement(mProfile);
            StateManager.instance().goTo(GameState.MENU, param, false);
            return;
        }
		
        if (mPaused) {
			if(mIsLoseScoreOK){ //score panel shown after losing, by pass
				mIsLoseScoreOK = false; //switch back to re-enable mPaused functionality
				return;
			}

            switch (mPauseSelectedItem) {
                case 0:
                    // continue
                    mPaused = !mPaused;
                    break;
                case 1:
                    // restart
                    initLevel();
                    break;
                case 2:
                    // quit
                    Vector param = new Vector();
                    param.addElement(mProfile);
                    StateManager.instance().goTo(GameState.MENU, param, false);
                    break;
            }
        }
	}

    protected void checkPause(long time, int keys) {
        if ((keys & GameCanvas.DOWN_PRESSED) != 0) {
            mPauseSelectedItem = (mPauseSelectedItem + 1) % mPauseStringItems.length;			
			if(mLosing)	if(mPauseSelectedItem <= 0) mPauseSelectedItem = 1;
        }
        if ((keys & GameCanvas.UP_PRESSED) != 0) {
            mPauseSelectedItem = (mPauseSelectedItem - 1 + mPauseStringItems.length) % mPauseStringItems.length;
			if(mLosing)	if(mPauseSelectedItem <= 0) mPauseSelectedItem = 2;
        }
    }

    protected void checkPlayer(long time, int keys) {
        mPlayer.update(time);

        // check each weapon
        Vector weapons = mPlayer.getWeapons();
        for (int i = 0, n = weapons.size(); i < n; ++i) {
            final Weapon weapon = (Weapon)weapons.elementAt(i);

            weapon.update(time);
            // check if seeking
            if (weapon.getData().isSeeking()) {
                // iterate all enemy, find first alive enemy
                for (int j = 0, m = mEnemies.size(); j < m; ++j) {
                    final Enemy enemy = (Enemy)mEnemies.elementAt(j);
                    if (enemy.isAlive() && enemy.isSpawned()) {
                        weapon.setNextTarget(enemy);
                        break;
                    }
                }
            }
        }

        // move player with game restriction
        mPlayer.position.y -= mScrollSpeed * time;

        final float playerVelocity = mPlayer.getData().getVelocity() / 100.0f;
        if ((keys & GameCanvas.LEFT_PRESSED) != 0) {
            mPlayer.position.x -= playerVelocity * time;
        }
        if ((keys & GameCanvas.RIGHT_PRESSED) != 0) {
            mPlayer.position.x += playerVelocity * time;
        }
        if ((keys & GameCanvas.DOWN_PRESSED) != 0) {
            mPlayer.position.y += playerVelocity * time;
        }
        if ((keys & GameCanvas.UP_PRESSED) != 0) {
            mPlayer.position.y -= playerVelocity * time;
        }

        final int top		= (int)(mDrawStartY + 10);
        final int left		= (int)(mDrawStartX + 10);
        final int bottom	= (int)(mDrawEndY - 30);
        final int right		= (int)(mDrawEndX - 10);

        if (mPlayer.position.y < top) {
            mPlayer.position.y = top;
        }
        if (mPlayer.position.y > bottom) {
            mPlayer.position.y = bottom;
        }
        if (mPlayer.position.x < left ) {
            mPlayer.position.x = left;
        }
        if (mPlayer.position.x > right) {
            mPlayer.position.x = right;
        }

        if (!mPlayer.isAlive()) {
            if (mPlayer.getLife() > 0)
                mParticleEmitters.addElement(ParticleEmitterFactory.customColorExplosionEmitter(mPlayer.position, 0xfb9f00));

            // respawn and reinitialize player position
            mPlayer.respawn();
            mPlayer.position.x  = mDrawStartX + StateManager.instance().getWidth() / 2;
            mPlayer.position.y  = mDrawStartY + StateManager.instance().getHeight() / 2;
        }
    }

	protected void checkEnemy(long time) {
		// check each enemy
		for (int i = 0, n = mEnemies.size(); i < n; ++i) {
			final Enemy enemy = (Enemy)mEnemies.elementAt(i);
            final EnemyData data = enemy.getData();

            // spawn enemy
			if (!enemy.isSpawned()) {
				// if enemy not yet spawned
				if (enemy.canSpawn((int)mDrawStartY)) {
					// if can spawn
					enemy.spawn();
				}
			} else {
                enemy.update(time);
                enemy.setTarget(mPlayer);
                if (!enemy.isAlive()) {
                    // killed by player? should explode? or is it killed because outside drawing area?
                    if (enemy.isShouldExplode()) {
                        // add player score
                        addScore(data.getScore());
                        ++mEnemyKilledCount;
                        // upon death, summon particles!
                        mParticleEmitters.addElement(ParticleEmitterFactory.customColorExplosionEmitter(enemy.position, data.getExplosionColor()));
                        // upon death, summon pickup!
                        PickupData pickupData = PickupFactory.instance().getPickupData(enemy.getPickupData());
                        if (pickupData != null) {
                            mPickups.addElement(new Pickup(pickupData, enemy.position));
                        }
                    }
                    // either way, delete it from the cycle
                    mDeleteEnemies.addElement(enemy);
                }
            }
		}

		// remove inactive enemy
		for (int i = 0, n = mDeleteEnemies.size(); i < n; ++i) {
			Enemy enemy = (Enemy)mDeleteEnemies.elementAt(i);
			mEnemies.removeElement(enemy);
		}
		mDeleteEnemies.removeAllElements();
	}

	protected void checkParticles(long time) {
		// check each particle emitters
		for (int i = 0, n = mParticleEmitters.size(); i < n; ++i) {
			ParticleEmitter emitter = (ParticleEmitter)mParticleEmitters.elementAt(i);
			emitter.update(time);
			if (!emitter.isAlive()) {
				mDeleteEmitters.addElement(emitter);
			}
		}

		// remove inactive emitter
		for (int i = 0, n = mDeleteEmitters.size(); i < n; ++i) {
			ParticleEmitter emitter = (ParticleEmitter)mDeleteEmitters.elementAt(i);
			mParticleEmitters.removeElement(emitter);
		}
		mDeleteEmitters.removeAllElements();
	}

    protected void checkPickups(long time) {
		// check each particle emitters
		for (int i = 0, n = mPickups.size(); i < n; ++i) {
			Pickup pickup = (Pickup)mPickups.elementAt(i);
			pickup.update(time);
			if (!pickup.isActive()) {
				mDeletePickups.addElement(pickup);
			}
		}

		// remove inactive emitter
		for (int i = 0, n = mDeletePickups.size(); i < n; ++i) {
			Pickup pickup = (Pickup)mDeletePickups.elementAt(i);
			mPickups.removeElement(pickup);
		}
		mDeletePickups.removeAllElements();
	}

    protected void checkEndCondition(long time) {
        if (mEnemies.isEmpty()) {
            mEndDelay += time;
            if (mEndDelay > END_DELAY) {
                endTheGame(false);
            }
        } else if (!mPlayer.isAlive() && mPlayer.getLife() <= 0) {
            // is dying and not respawning
            mEndDelay += time;
            if (mEndDelay > END_DELAY) {
                endTheGame(true);
            }
        }
    }

    protected void endTheGame(boolean isLosing) {
        mPaused = true;
		mIsLoseScoreOK = true;
        final int enemyKilledPercentage = mEnemyKilledCount * 100 / mInitialEnemyCount;
        final int lifePercentage        = (int)(((float)mPlayer.getLife() + (float)mPlayer.getHealth() / (float)mPlayer.getData().getHealthMax() ) * 100.0f / (float)mInitialLifeCount);
        final float awesomeness         = (float)(enemyKilledPercentage + lifePercentage) / 200.0f;
        final int moneyAdded            = (int)((float)mPlayer.getScore() * awesomeness);

        try {
            if (isLosing) {
                mRankImage = Image.createImage(Utilities.INTERFACE_FOLDER + "/rank_e.png");
                mFinalScore = 0;
            } else if (awesomeness >= 0.95f) {
                mRankImage = Image.createImage(Utilities.INTERFACE_FOLDER + "/rank_s.png");
                mFinalScore = 5;
            } else if (awesomeness >= 0.85f) {
                mRankImage = Image.createImage(Utilities.INTERFACE_FOLDER + "/rank_a.png");
                mFinalScore = 4;
            } else if (awesomeness >= 0.75f) {
                mRankImage = Image.createImage(Utilities.INTERFACE_FOLDER + "/rank_b.png");
                mFinalScore = 3;
            } else if (awesomeness >= 0.50f) {
                mRankImage = Image.createImage(Utilities.INTERFACE_FOLDER + "/rank_c.png");
                mFinalScore = 2;
            } else {
                mRankImage = Image.createImage(Utilities.INTERFACE_FOLDER + "/rank_d.png");
                mFinalScore = 1;
            }
        } catch (IOException iEx) {

        }

        mScoreValueStringImage  = new Image[3];
        mScoreValueStringImage[0]   = BitmapFont.getFont(BitmapFont.BITSUMISHI_BLUE).renderTransparentText(enemyKilledPercentage + "%", 0x000000);
        mScoreValueStringImage[1]   = BitmapFont.getFont(BitmapFont.BITSUMISHI_BLUE).renderTransparentText(lifePercentage + "%", 0x000000);
        mScoreValueStringImage[2]   = BitmapFont.getFont(BitmapFont.BITSUMISHI_BLUE).renderTransparentText("" + moneyAdded, 0x000000);
        if (isLosing) {
            mLosing = true;
			mPauseSelectedItem = 1; //Defaulted to 'restart'
        } else {
            mWinning = true;
			StateManager.instance().getSimplePlayer().setSong(Utilities.BGM_FOLDER + "/win.mid", "audio/mid", SimplePlayer.LOOP_INF);
			StateManager.instance().getSimplePlayer().startPlayer();
        }
        mProfile.addMoney(moneyAdded);
    }

    protected void checkCollision() {
        // check enemy-player collision
        final int playerSize = mPlayer.getData().getBodySize();
        for (int i = 0, n = mEnemies.size(); i < n; ++i) {
            final Enemy enemy       = (Enemy)mEnemies.elementAt(i);
            if (!enemy.isSpawned() || !enemy.isAlive()) continue;
            final EnemyData data    = enemy.getData();

			if (mPlayer.collide(enemy, playerSize + data.getBodySize())) {
				// is colliding

				// reduce enemy health equal to player current health
                final int damage = Math.min(mPlayer.getHealth(), enemy.getHealth());
				enemy.damage(damage);
                mPlayer.damage(damage);
			}
        }

        // check pickup-player collision
        for (int i = 0, n = mPickups.size(); i < n; ++i) {
            Pickup pickup = (Pickup)mPickups.elementAt(i);

			if (mPlayer.collide(pickup, playerSize + 5)) {
				// is colliding

				pickup.picked();
                addScore(pickup.getData().getScore());
                mPlayer.addHealth(pickup.getData().getHealth());
                mPlayer.addLife(pickup.getData().getLife());
			}
        }

        // check enemy-bullet collision
        final Vector playerWeapons = mPlayer.getWeapons();
        // for each weapon
        for (int i = 0, n = playerWeapons.size(); i < n; ++i) {
            final Weapon weapon = (Weapon)playerWeapons.elementAt(i);
            final Vector bullets = weapon.getBullets();
            // for each bullet in that weapon
            for (int j = 0, m = bullets.size(); j < m; ++j) {
                final Bullet bullet         = (Bullet)bullets.elementAt(j);
                final float bulletArea      = bullet.getData().getArea();
                final int bulletDamage      = bullet.getData().getDamage();
                // for each enemy
                for (int k = 0, p = mEnemies.size(); k < p; ++k) {
                    final Enemy enemy = (Enemy)mEnemies.elementAt(k);
                    if (!enemy.isSpawned() || !enemy.isAlive()) continue;
                    final int enemySize = enemy.getData().getBodySize();
                    boolean isColliding = false;
                    if (bullet.isExploding()) {
                        isColliding = bullet.collide(enemy, bulletArea + enemySize);
                    } else {
                        isColliding = bullet.collide(enemy, enemySize + 10);
                    }
                    if (isColliding) {
                        if (!bullet.isExploding()) {
                            bullet.explode();
                            mParticleEmitters.addElement(ParticleEmitterFactory.customColorHitEmitter(bullet.position, bullet.getDirection(), bullet.getData().getExplosionColor()));
                        }
                        enemy.damage(bulletDamage);
                    }
                }
            }
        }
        // check player-bullet collision
        // for each enemy
        for (int i = 0, n = mEnemies.size(); i < n; ++i) {
            final Enemy enemy = (Enemy)mEnemies.elementAt(i);
            if (!enemy.isAlive() || !enemy.isSpawned()) continue;
            final Vector bullets = enemy.getBullets();
            // for each bullet in that enemy
            for (int j = 0, m = bullets.size(); j < m; ++j) {
                final Bullet bullet         = (Bullet)bullets.elementAt(j);
                final float bulletArea      = bullet.getData().getArea();
                final int bulletDamage      = bullet.getData().getDamage();
                boolean isColliding = false;
                if (bullet.isExploding()) {
                    isColliding = bullet.collide(mPlayer, bulletArea + playerSize);
                } else {
                    isColliding = bullet.collide(mPlayer, playerSize + 10);
                }
                if (isColliding) {
                    if (!bullet.isExploding()) {
                        mParticleEmitters.addElement(ParticleEmitterFactory.customColorHitEmitter(bullet.position, bullet.getDirection(), bullet.getData().getExplosionColor()));
                        bullet.explode();
                    }
                    mPlayer.damage(bulletDamage);
                }
            }
        }
    }

	public void draw(Graphics g) {
		g.fillRect((int)mDrawStartX, 0, (int)mDrawEndX, StateManager.instance().getHeight());
		
		//Draw map
		mLevel.getMap().draw(g, (int)mDrawStartX, (int)mDrawStartY, (int)mDrawEndX, (int)mDrawEndY);

        // draw entities
		drawEntities(g);

        // draw interfaces
        drawInterfaces(g);
	}

	protected void drawEntities(Graphics g) {
		// draw enemies
        for (int i = 0, n = mEnemies.size(); i < n; ++i) {
            Enemy enemy = (Enemy)mEnemies.elementAt(i);
            enemy.draw(g, (int)mDrawStartX, (int)mDrawStartY, (int)mDrawEndX, (int)mDrawEndY);
        }

		// draw particles
		for (int i = 0, n = mParticleEmitters.size(); i < n; ++i) {
			ParticleEmitter emitter = (ParticleEmitter)mParticleEmitters.elementAt(i);
			emitter.draw(g, (int)mDrawStartX, (int)mDrawStartY, (int)mDrawEndX, (int)mDrawEndY);
		}

        // draw pickups
        for (int i = 0, n = mPickups.size(); i < n; ++i) {
			Pickup pickup = (Pickup)mPickups.elementAt(i);
			pickup.draw(g, (int)mDrawStartX, (int)mDrawStartY, (int)mDrawEndX, (int)mDrawEndY);
		}

        // draw player
		mPlayer.draw(g, (int)mDrawStartX, (int)mDrawStartY, (int)mDrawEndX, (int)mDrawEndY);
	}

    protected void drawInterfaces(Graphics g) {
        final int stateWidth05  = StateManager.instance().getWidth() / 2;
        final int stateHeight05 = StateManager.instance().getHeight() / 2;
        if (mPaused && !mIsLoseScoreOK) {
            g.drawImage(StateManager.instance().getDarkImage(), 0, 0, Graphics.LEFT | Graphics.TOP);
            if (!mWinning) {
                g.drawImage(mPauseBoardImage, StateManager.instance().getWidth() / 2, StateManager.instance().getHeight() / 2, Graphics.VCENTER | Graphics.HCENTER);
                for (int i = -1; i <= 1; ++i) {
                    g.drawImage(mPauseStringItems[i + 1], stateWidth05, stateHeight05 + 20 * i, Graphics.VCENTER | Graphics.HCENTER);
                }
				g.drawImage(mPauseSelectionImage, stateWidth05, stateHeight05 + 20 * (mPauseSelectedItem-1), Graphics.VCENTER | Graphics.HCENTER);
            }
        }
		
        g.drawImage(mProfileBoard, 1, 1, Graphics.TOP | Graphics.LEFT);
        g.drawImage(mScoreStringImage, 45, 17, Graphics.TOP | Graphics.LEFT);
        final int reduct = (mPlayer.getData().getHealthMax() - mPlayer.getHealth()) * mHealthBar.getWidth() / mPlayer.getData().getHealthMax();
        g.drawRegion(mHealthBar, 0, 0, mHealthBar.getWidth() - reduct, mHealthBar.getHeight(), 0, 45, 30, Graphics.TOP | Graphics.LEFT);
        for (int i = 0; i < mPlayer.getLife(); ++i) {
            g.drawImage(mLife, 45 + i * 10, 43, Graphics.TOP | Graphics.LEFT);
        }

        if ( (mWinning || mLosing) && mIsLoseScoreOK) {
            g.drawImage(mScoreBoardImage, StateManager.instance().getWidth() / 2, StateManager.instance().getHeight() / 2, Graphics.VCENTER | Graphics.HCENTER);
            for (int i = 0; i < 3; ++i) {
                g.drawImage(mScoreLabelStringImage[i], 85, 70 + i * 20, Graphics.TOP | Graphics.LEFT);
            }
            g.drawImage(mScoreLabelStringImage[3], 85, 155,    Graphics.TOP | Graphics.LEFT);

            for (int i = 0; i < 2; ++i) {
                g.drawImage(mScoreValueStringImage[i], 245, 70 + i * 20, Graphics.TOP | Graphics.RIGHT);
            }
            g.drawImage(mScoreValueStringImage[2],  245, 125,    Graphics.TOP | Graphics.RIGHT);
            g.drawImage(mRankImage,                 245, 143,    Graphics.TOP | Graphics.RIGHT);

            if (mBlinkingTime / 1000 % 2 == 0) {
                g.drawImage(mPressFireStringImage, StateManager.instance().getWidth() / 2, StateManager.instance().getHeight() / 2 + 100, Graphics.VCENTER | Graphics.HCENTER);
            }
        }
    }

	//Entities
	protected Level mLevel;
	protected Vector mParticleEmitters;
	protected Vector mEnemies;
    protected Vector mPickups;
	protected Player mPlayer;

	// Deleting entities
	protected Vector mDeleteEmitters;
	protected Vector mDeleteEnemies;
    protected Vector mDeletePickups;

	//Gameplay variable
	protected float mScrollSpeed;
    protected boolean mPaused;
	
	//Data
	protected int mCurrentLevel;
    protected Profile mProfile;

	//Components
    protected Image mProfileBoard;
    protected Image mHealthBar;
    protected Image mLife;
	
	//Draw area
	protected float mDrawEndX;
	protected float mDrawEndY;
	protected float mDrawStartX;
	protected float mDrawStartY;

    // pause stuffs
    protected int mPauseSelectedItem;
    protected Image mPauseBoardImage, mPauseSelectionImage;
    protected Image[] mPauseStringItems;

    // winning stuffs
    protected int mEndDelay;
    protected int mInitialEnemyCount;
    protected int mEnemyKilledCount;
    protected int mInitialLifeCount;
    protected boolean mWinning, mLosing;
    protected long mBlinkingTime;
    protected int mFinalScore;
	protected boolean mIsLoseScoreOK;

    // scoring images
    protected Image mScoreBoardImage;
    protected Image mScoreStringImage;
    protected Image[] mScoreLabelStringImage;
    protected Image[] mScoreValueStringImage;
    protected Image mRankImage;
    protected Image mPressFireStringImage;

    // delay 3 sec before winning
    protected final static int END_DELAY = 1000;
}
